home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / OLDBARS.PAK / TOOLBAR.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  35.5 KB  |  1,361 lines

  1. // toolbar.cpp : definition of old backward compatible CToolBar
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #define _AFX_NO_OLE_SUPPORT
  15. #include <afxpriv.h>
  16. #include "toolbar.h"
  17. #include "globals.h"
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24. #define new DEBUG_NEW
  25.  
  26. // globals for fast drawing (shared globals)
  27. #ifndef _MAC
  28. static HDC hDCGlyphs = NULL;
  29. static HDC hDCMono = NULL;
  30. #else
  31. #define hDCGlyphs   m_hDCGlyphs
  32. #define hDCMono     m_hDCMono
  33. #endif
  34. static HBRUSH hbrDither = NULL;
  35.  
  36. /////////////////////////////////////////////////////////////////////////////
  37. // Init / Term
  38.  
  39. #ifndef _MAC
  40. static HBITMAP AFXAPI CreateDitherBitmap();
  41. #else
  42. static HBITMAP AFXAPI CreateDitherBitmap(BOOL bMonochrome);
  43. #endif
  44.  
  45. #ifdef AFX_INIT_SEG
  46. #pragma code_seg(AFX_INIT_SEG)
  47. #endif
  48.  
  49.  
  50.  
  51. // a special struct that will cleanup automatically
  52. struct _AFX_TOOLBAR_TERM
  53. {
  54.     ~_AFX_TOOLBAR_TERM()
  55.     {
  56. #ifndef _MAC
  57.         AfxDeleteObject((HGDIOBJ*)&hDCMono);
  58.         AfxDeleteObject((HGDIOBJ*)&hDCGlyphs);
  59. #endif
  60.         AfxDeleteObject((HGDIOBJ*)&hbrDither);
  61.     }
  62. };
  63.  
  64. static const _AFX_TOOLBAR_TERM toolbarTerm;
  65.  
  66. /////////////////////////////////////////////////////////////////////////////
  67.  
  68. #ifdef AFX_CORE3_SEG
  69. #pragma code_seg(AFX_CORE3_SEG)
  70. #endif
  71.  
  72. #ifndef _MAC
  73. static HBITMAP AFXAPI CreateDitherBitmap()
  74. #else
  75. static HBITMAP AFXAPI CreateDitherBitmap(BOOL bMonochrome)
  76. #endif
  77. {
  78.     struct  // BITMAPINFO with 16 colors
  79.     {
  80.         BITMAPINFOHEADER bmiHeader;
  81.         RGBQUAD      bmiColors[16];
  82.     } bmi;
  83.     memset(&bmi, 0, sizeof(bmi));
  84.  
  85.     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  86.     bmi.bmiHeader.biWidth = 8;
  87.     bmi.bmiHeader.biHeight = 8;
  88.     bmi.bmiHeader.biPlanes = 1;
  89.     bmi.bmiHeader.biBitCount = 1;
  90.     bmi.bmiHeader.biCompression = BI_RGB;
  91.  
  92.     COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
  93. #ifdef _MAC
  94.     // if monochrome or the face color is already white, use black instead to make
  95.     // sure that we draw a dither - otherwise we'll have a white on white bitmap
  96.     if (bMonochrome || clr == RGB(255, 255, 255))
  97.         clr = 0;
  98. #endif
  99.     bmi.bmiColors[0].rgbBlue = GetBValue(clr);
  100.     bmi.bmiColors[0].rgbGreen = GetGValue(clr);
  101.     bmi.bmiColors[0].rgbRed = GetRValue(clr);
  102.  
  103.     clr = ::GetSysColor(COLOR_BTNHIGHLIGHT);
  104.     bmi.bmiColors[1].rgbBlue = GetBValue(clr);
  105.     bmi.bmiColors[1].rgbGreen = GetGValue(clr);
  106.     bmi.bmiColors[1].rgbRed = GetRValue(clr);
  107.  
  108.     // initialize the brushes
  109.     long patGray[8];
  110.     for (int i = 0; i < 8; i++)
  111.        patGray[i] = (i & 1) ? 0xAAAA5555L : 0x5555AAAAL;
  112.  
  113.     HDC hDC = GetDC(NULL);
  114.     HBITMAP hbm = CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT,
  115.         (LPBYTE)patGray, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
  116.     ReleaseDC(NULL, hDC);
  117.  
  118.     return hbm;
  119. }
  120.  
  121. // create a mono bitmap mask:
  122. void CToolBar::CreateMask(int iImage, CPoint ptOffset,
  123.      BOOL bHilite, BOOL bHiliteShadow)
  124. {
  125.     // initalize whole area with 0's
  126.     PatBlt(hDCMono, 0, 0, m_sizeButton.cx-2, m_sizeButton.cy-2, WHITENESS);
  127.  
  128.     // create mask based on color bitmap
  129.     // convert this to 1's
  130.     SetBkColor(hDCGlyphs, globalData.clrBtnFace);
  131.     BitBlt(hDCMono, ptOffset.x, ptOffset.y, m_sizeImage.cx, m_sizeImage.cy,
  132.         hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);
  133.  
  134.     if (bHilite)
  135.     {
  136.         // convert this to 1's
  137.         SetBkColor(hDCGlyphs, globalData.clrBtnHilite);
  138.  
  139.         // OR in the new 1's
  140.         BitBlt(hDCMono, ptOffset.x, ptOffset.y, m_sizeImage.cx, m_sizeImage.cy,
  141.             hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCPAINT);
  142.  
  143.         if (bHiliteShadow)
  144.             BitBlt(hDCMono, 1, 1, m_sizeButton.cx-3, m_sizeButton.cy-3,
  145.                 hDCMono, 0, 0, SRCAND);
  146.     }
  147. }
  148.  
  149. // Raster Ops
  150. #define ROP_DSPDxax  0x00E20746L
  151. #define ROP_PSDPxax  0x00B8074AL
  152.  
  153. BOOL CToolBar::DrawButton(CDC* pDC, int x, int y, int iImage, UINT nStyle)
  154. {
  155.     ASSERT_VALID(pDC);
  156.  
  157.     int dx = m_sizeButton.cx;
  158.     int dy = m_sizeButton.cy;
  159.     if (!globalData.bWin4)
  160.     {
  161.         // make the coordinates the interior of the button
  162.         x += 1;
  163.         y += 1;
  164.         dx -= 2;
  165.         dy -= 2;
  166.  
  167.         // border around button
  168.         pDC->FillSolidRect(x,    y-1,    dx, 1,  globalData.clrWindowFrame);
  169.         pDC->FillSolidRect(x,    y+dy,   dx, 1,  globalData.clrWindowFrame);
  170.         pDC->FillSolidRect(x-1,  y,  1,  dy, globalData.clrWindowFrame);
  171.         pDC->FillSolidRect(x+dx, y,  1,  dy, globalData.clrWindowFrame);
  172.     }
  173.  
  174. #ifdef _MAC
  175.     if (m_bMonochrome)
  176.         return DrawMonoButton(pDC, x, y, dx, dy, iImage, nStyle);
  177. #endif
  178.  
  179.     // interior grey
  180.     pDC->FillSolidRect(x, y, dx, dy, globalData.clrBtnFace);
  181.  
  182.     // determine offset of bitmap (centered within button)
  183.     CPoint ptOffset;
  184.     ptOffset.x = (dx - m_sizeImage.cx - 1) / 2;
  185.     ptOffset.y = (dy - m_sizeImage.cy) / 2;
  186.  
  187.     if (nStyle & (TBBS_PRESSED | TBBS_CHECKED))
  188.     {
  189.         // pressed in or checked
  190.         pDC->Draw3dRect(x, y, dx, dy,
  191.             globalData.bWin4 ? globalData.clrWindowFrame : globalData.clrBtnShadow,
  192.             globalData.bWin4 ? globalData.clrBtnHilite : globalData.clrBtnFace);
  193.  
  194.         if (globalData.bWin4)
  195.         {
  196.             pDC->Draw3dRect(x + 1, y + 1, dx - 2, dy - 2,
  197.                 globalData.clrBtnShadow, globalData.clrBtnFace);
  198.         }
  199.  
  200.         // for any depressed button, add one to the offsets.
  201.         ptOffset.x += 1;
  202.         ptOffset.y += 1;
  203.     }
  204.     else
  205.     {
  206.         // regular button look
  207.         pDC->Draw3dRect(x, y, dx, dy, globalData.clrBtnHilite,
  208.             globalData.bWin4 ? globalData.clrWindowFrame : globalData.clrBtnShadow);
  209.         pDC->Draw3dRect(x + 1, y + 1, dx - 2, dy - 2,
  210.             globalData.clrBtnFace, globalData.clrBtnShadow);
  211.     }
  212.  
  213.     if ((nStyle & TBBS_PRESSED) || !(nStyle & TBBS_DISABLED))
  214.     {
  215.         // normal image version
  216.         BitBlt(pDC->m_hDC, x + ptOffset.x, y + ptOffset.y,
  217.             m_sizeImage.cx, m_sizeImage.cy,
  218.             hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);
  219.  
  220.         if (nStyle & TBBS_PRESSED)
  221.             return TRUE;        // nothing more to do (rest of style is ignored)
  222.     }
  223.  
  224.     if (nStyle & (TBBS_DISABLED | TBBS_INDETERMINATE))
  225.     {
  226.         // disabled or indeterminate version
  227.         CreateMask(iImage, ptOffset, TRUE, FALSE);
  228.  
  229.         pDC->SetTextColor(0L);                  // 0's in mono -> 0 (for ROP)
  230.         pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1's in mono -> 1
  231.  
  232.         if (nStyle & TBBS_DISABLED)
  233.         {
  234.             // disabled - draw the hilighted shadow
  235.             HGDIOBJ hbrOld = pDC->SelectObject(globalData.hbrBtnHilite);
  236.             if (hbrOld != NULL)
  237.             {
  238.                 // draw hilight color where we have 0's in the mask
  239.                 BitBlt(pDC->m_hDC, x + 1, y + 1,
  240.                     m_sizeButton.cx - 2, m_sizeButton.cy - 2,
  241.                     hDCMono, 0, 0, ROP_PSDPxax);
  242.                 pDC->SelectObject(hbrOld);
  243.             }
  244.         }
  245.  
  246.         //BLOCK: always draw the shadow
  247.         {
  248.             HGDIOBJ hbrOld = pDC->SelectObject(globalData.hbrBtnShadow);
  249.             if (hbrOld != NULL)
  250.             {
  251.                 // draw the shadow color where we have 0's in the mask
  252.                 BitBlt(pDC->m_hDC, x, y,
  253.                     m_sizeButton.cx - 2, m_sizeButton.cy - 2,
  254.                     hDCMono, 0, 0, ROP_PSDPxax);
  255.                 pDC->SelectObject(hbrOld);
  256.             }
  257.         }
  258.     }
  259.  
  260.     // if it is checked do the dither brush avoiding the glyph
  261.     if (nStyle & (TBBS_CHECKED | TBBS_INDETERMINATE))
  262.     {
  263.         HGDIOBJ hbrOld = pDC->SelectObject(hbrDither);
  264.         if (hbrOld != NULL)
  265.         {
  266.             ptOffset.x -= globalData.cxBorder2;
  267.             ptOffset.y -= globalData.cyBorder2;
  268.             CreateMask(iImage, ptOffset, ~(nStyle & TBBS_INDETERMINATE),
  269.                     nStyle & TBBS_DISABLED);
  270.  
  271.             pDC->SetTextColor(0L);              // 0 -> 0
  272.             pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1 -> 1
  273.  
  274.             ASSERT(globalData.cxBorder2 == globalData.cyBorder2);
  275.             int delta = (nStyle & TBBS_INDETERMINATE) ?
  276.                 globalData.bWin4 ? globalData.cxBorder2*2 : 3 : globalData.cxBorder2*2;
  277.  
  278.             // only draw the dither brush where the mask is 1's
  279.             BitBlt(pDC->m_hDC,
  280.                 x + globalData.cxBorder2, y + globalData.cyBorder2, dx-delta, dy-delta,
  281.                 hDCMono, 0, 0, ROP_DSPDxax);
  282.             pDC->SelectObject(hbrOld);
  283.         }
  284.     }
  285.  
  286.     return TRUE;
  287. }
  288.  
  289. #ifdef _MAC
  290. BOOL CToolBar::DrawMonoButton(CDC* pDC, int x, int y, int dx, int dy,
  291.     int iImage, UINT nStyle)
  292. {
  293.     // interior is black if pressed, white if not
  294.     if (nStyle & (TBBS_PRESSED | TBBS_CHECKED))
  295.     {
  296.         pDC->FillSolidRect(x, y, dx, dy, RGB(0, 0, 0));
  297.         pDC->SetBkColor(RGB(255, 255, 255));    // bkcolor was set by PatB
  298.     }
  299.     else
  300.     {
  301.         pDC->FillSolidRect(x, y, dx, dy, RGB(0xFF, 0xFF, 0xFF));
  302.     }
  303.  
  304.     CPoint ptOffset;
  305.     ptOffset.x = (dx - m_sizeImage.cx - 1) / 2;
  306.     ptOffset.y = (dy - m_sizeImage.cy) / 2;
  307.  
  308.     if ((nStyle & TBBS_PRESSED) || !(nStyle & TBBS_DISABLED))
  309.     {
  310.         // normal image version
  311.         BitBlt(pDC->m_hDC, x + ptOffset.x, y + ptOffset.y, m_sizeImage.cx,
  312.             m_sizeImage.cy, hDCGlyphs, iImage * m_sizeImage.cx, 0,
  313.             (nStyle & (TBBS_PRESSED | TBBS_CHECKED)) ? NOTSRCCOPY : SRCCOPY);
  314.  
  315.         if (nStyle & (TBBS_PRESSED | TBBS_CHECKED))
  316.             return TRUE;        // nothing more to do (rest of style is ignored)
  317.     }
  318.  
  319.     if (nStyle & TBBS_DISABLED)
  320.     {
  321.         BitBlt(pDC->m_hDC, x + ptOffset.x, y + ptOffset.y, m_sizeImage.cx,
  322.             m_sizeImage.cy, hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);
  323.  
  324.         int ropOld = pDC->SetROP2(R2_MASKNOTPEN);
  325.         RECT rect;
  326.         SetRect(&rect, 0, 0, m_sizeImage.cx, m_sizeImage.cy);
  327.         OffsetRect(&rect, x + ptOffset.x, y + ptOffset.y);
  328.         AfxFillRect(pDC->m_hDC, &rect, hbrDither);
  329.         pDC->SetROP2(ropOld);
  330.  
  331.         return TRUE;
  332.     }
  333.  
  334.     // if it is checked do the dither brush avoiding the glyph
  335.     if (nStyle & (TBBS_CHECKED | TBBS_INDETERMINATE))
  336.     {
  337.         HGDIOBJ hbrOld = pDC->SelectObject(hbrDither);
  338.         if (hbrOld != NULL)
  339.         {
  340.             CreateMask(iImage, ptOffset, ~(nStyle & TBBS_INDETERMINATE),
  341.                     nStyle & TBBS_DISABLED);
  342.  
  343.             pDC->SetTextColor(0L);              // 0 -> 0
  344.             pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1 -> 1
  345.  
  346.             int delta = (nStyle & TBBS_INDETERMINATE) ? 3 : 1;
  347.  
  348.             // only draw the dither brush where the mask is 1's
  349.             CRect rect(0, 0, dx, dy);
  350.             ::InvertRect(hDCMono, &rect);
  351.  
  352.             BitBlt(pDC->m_hDC, x, y, dx, dy, hDCMono, 0, 0, ROP_PSDPxax);
  353.             pDC->SelectObject(hbrOld);
  354.         }
  355.     }
  356.  
  357.     return TRUE;
  358. }
  359. #endif
  360.  
  361. BOOL CToolBar::PrepareDrawButton(DrawState& ds)
  362. {
  363.     ASSERT(m_hbmImageWell != NULL);
  364.     ASSERT(m_sizeButton.cx > 2 && m_sizeButton.cy > 2);
  365.  
  366.     // We need to kick-start the bitmap selection process.
  367.     ds.hbmOldGlyphs = (HBITMAP)SelectObject(hDCGlyphs, m_hbmImageWell);
  368.     ds.hbmMono = CreateBitmap(m_sizeButton.cx-2, m_sizeButton.cy-2,
  369.                     1, 1, NULL);
  370.     ds.hbmMonoOld = (HBITMAP)SelectObject(hDCMono, ds.hbmMono);
  371.     if (ds.hbmOldGlyphs == NULL || ds.hbmMono == NULL || ds.hbmMonoOld == NULL)
  372.     {
  373.         TRACE0("Error: can't draw toolbar.\n");
  374.         AfxDeleteObject((HGDIOBJ*)&ds.hbmMono);
  375.         return FALSE;
  376.     }
  377.     return TRUE;
  378. }
  379.  
  380. void CToolBar::EndDrawButton(DrawState& ds)
  381. {
  382.     SelectObject(hDCMono, ds.hbmMonoOld);
  383.     AfxDeleteObject((HGDIOBJ*)&ds.hbmMono);
  384.     SelectObject(hDCGlyphs, ds.hbmOldGlyphs);
  385. }
  386.  
  387. /////////////////////////////////////////////////////////////////////////////
  388. // CToolBar creation etc
  389.  
  390. struct AFX_TBBUTTON
  391. {
  392.     UINT nID;        // Command ID that this button sends
  393.     UINT nStyle;    // TBBS_ styles
  394.     int iImage;     // index into mondo bitmap of this button's picture
  395.                         // or size of this spacer
  396. };
  397.  
  398. inline AFX_TBBUTTON* CToolBar::_GetButtonPtr(int nIndex) const
  399. {
  400.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  401.     ASSERT(m_pData != NULL);
  402.     return ((AFX_TBBUTTON*)m_pData) + nIndex;
  403. }
  404.  
  405. /*
  406.     DIBs use RGBQUAD format:
  407.         0xbb 0xgg 0xrr 0x00
  408.  
  409.     Reasonably efficient code to convert a COLORREF into an
  410.     RGBQUAD is byte-order-dependent, so we need different
  411.     code depending on the byte order we're targeting.
  412. */
  413. #ifndef _MAC
  414. #define RGB_TO_RGBQUAD(r,g,b)   (RGB(b,g,r))
  415. #define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
  416. #else
  417. #define RGB_TO_RGBQUAD(r,g,b)   (RGB(r,g,b) << 8)
  418. #define CLR_TO_RGBQUAD(clr)     (clr << 8)
  419. #endif
  420.  
  421. #ifndef _MAC
  422. HBITMAP AFXAPI LoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc)
  423. #else
  424. HBITMAP AFXAPI LoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc,
  425.     HDC hDCGlyphs, BOOL bMonochrome)
  426. #endif
  427. {
  428.     struct COLORMAP
  429.     {
  430.         // use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
  431.         DWORD rgbqFrom;
  432.         int iSysColorTo;
  433.     };
  434.     static const COLORMAP sysColorMap[] =
  435.     {
  436.         // mapping from color in DIB to system color
  437.         { RGB_TO_RGBQUAD(0x00, 0x00, 0x00),  COLOR_BTNTEXT },       // black
  438.         { RGB_TO_RGBQUAD(0x80, 0x80, 0x80),  COLOR_BTNSHADOW },     // dark grey
  439.         { RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0),  COLOR_BTNFACE },       // bright grey
  440.         { RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF),  COLOR_BTNHIGHLIGHT }   // white
  441.     };
  442.     const int nMaps = 4;
  443.  
  444.     HGLOBAL hglb;
  445.     if ((hglb = ::LoadResource(hInst, hRsrc)) == NULL)
  446.         return NULL;
  447.  
  448.     LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
  449.     if (lpBitmap == NULL)
  450.         return NULL;
  451.  
  452.     // make copy of BITMAPINFOHEADER so we can modify the color table
  453.     const int nColorTableSize = 16;
  454.     UINT nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
  455.     LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
  456.     if (lpBitmapInfo == NULL)
  457.         return NULL;
  458.     memcpy(lpBitmapInfo, lpBitmap, nSize);
  459.  
  460.     // color table is in RGBQUAD DIB format
  461.     DWORD* pColorTable =
  462.         (DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);
  463.  
  464.     for (int iColor = 0; iColor < nColorTableSize; iColor++)
  465.     {
  466.         // look for matching RGBQUAD color in original
  467.         for (int i = 0; i < nMaps; i++)
  468.         {
  469.             if (pColorTable[iColor] == sysColorMap[i].rgbqFrom)
  470.             {
  471. #ifdef _MAC
  472.                 if (bMonochrome)
  473.                 {
  474.                     // all colors except text become white
  475.                     if (sysColorMap[i].iSysColorTo != COLOR_BTNTEXT)
  476.                         pColorTable[iColor] = RGB_TO_RGBQUAD(255, 255, 255);
  477.                 }
  478.                 else
  479. #endif
  480.                 pColorTable[iColor] =
  481.                     CLR_TO_RGBQUAD(::GetSysColor(sysColorMap[i].iSysColorTo));
  482.                 break;
  483.             }
  484.         }
  485.     }
  486.  
  487.     int nWidth = (int)lpBitmapInfo->biWidth;
  488.     int nHeight = (int)lpBitmapInfo->biHeight;
  489.     HDC hDCScreen = ::GetDC(NULL);
  490.     HBITMAP hbm = ::CreateCompatibleBitmap(hDCScreen, nWidth, nHeight);
  491.     ::ReleaseDC(NULL, hDCScreen);
  492.  
  493.     if (hbm != NULL)
  494.     {
  495.         HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);
  496.  
  497.         LPBYTE lpBits;
  498.         lpBits = (LPBYTE)(lpBitmap + 1);
  499.         lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
  500.  
  501.         StretchDIBits(hDCGlyphs, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
  502.             lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  503.         SelectObject(hDCGlyphs, hbmOld);
  504.  
  505. #ifdef _MAC
  506.         // We don't change this bitmap any more, so get rid of the big,
  507.         // wasteful Macintosh port
  508.         ::SetBitmapReadOnly(hbm, BRO_READONLY);
  509. #endif
  510.     }
  511.  
  512.     // free copy of bitmap info struct and resource itself
  513.     ::free(lpBitmapInfo);
  514.     ::FreeResource(hglb);
  515.  
  516.     return hbm;
  517. }
  518.  
  519. #ifdef AFX_INIT_SEG
  520. #pragma code_seg(AFX_INIT_SEG)
  521. #endif
  522.  
  523. CToolBar::CToolBar()
  524. {
  525.     m_hbmImageWell = NULL;
  526.     m_hInstImageWell = NULL;
  527.     m_hRsrcImageWell = NULL;
  528.     m_iButtonCapture = -1;      // nothing captured
  529.  
  530.     // UISG standard sizes
  531.     m_sizeButton.cx = 24;
  532.     m_sizeButton.cy = 22;
  533.     m_sizeImage.cx = 16;
  534.     m_sizeImage.cy = 15;
  535.     m_cyTopBorder = m_cyBottomBorder = 3;   // 3 pixel for top/bottom gaps
  536.  
  537.     // adjust sizes when running on Win4
  538.     if (globalData.bWin4)
  539.     {
  540.         m_sizeButton.cx = 23;
  541.         m_cySharedBorder = m_cxSharedBorder = 0;
  542.         m_cxDefaultGap = 8;
  543.     }
  544.     else
  545.     {
  546.         m_cxDefaultGap = 6;
  547.         m_cySharedBorder = m_cxSharedBorder = 1;
  548.     }
  549.  
  550. #ifdef _MAC
  551.     m_hDCGlyphs = CreateCompatibleDC(NULL);
  552.     m_hDCMono = ::CreateCompatibleDC(NULL);
  553.     if (m_hDCGlyphs == NULL || m_hDCMono == NULL)
  554.         AfxThrowResourceException();
  555. #endif
  556.  
  557.     // initialize the toolbar drawing engine
  558.     static BOOL bInitialized;
  559.     if (!bInitialized)
  560.     {
  561. #ifndef _MAC
  562.         hDCGlyphs = CreateCompatibleDC(NULL);
  563.  
  564.         // Mono DC and Bitmap for disabled image
  565.         hDCMono = ::CreateCompatibleDC(NULL);
  566. #endif
  567.  
  568. #ifndef _MAC
  569.         HBITMAP hbmGray = ::CreateDitherBitmap();
  570. #else
  571.         HBITMAP hbmGray = ::CreateDitherBitmap(m_bMonochrome);
  572. #endif
  573.         if (hbmGray != NULL)
  574.         {
  575.             ASSERT(hbrDither == NULL);
  576.             hbrDither = ::CreatePatternBrush(hbmGray);
  577.             AfxDeleteObject((HGDIOBJ*)&hbmGray);
  578.         }
  579.  
  580. #ifndef _MAC
  581.         if (hDCGlyphs == NULL || hDCMono == NULL || hbrDither == NULL)
  582.             AfxThrowResourceException();
  583. #else
  584.         if (hbrDither == NULL)
  585.             AfxThrowResourceException();
  586. #endif
  587.         bInitialized = TRUE;
  588.     }
  589. }
  590.  
  591. CToolBar::~CToolBar()
  592. {
  593. #ifdef _MAC
  594.     ASSERT(m_hDCGlyphs != NULL);
  595.     VERIFY(::DeleteDC(m_hDCGlyphs));
  596.  
  597.     ASSERT(m_hDCMono != NULL);
  598.     VERIFY(::DeleteDC(m_hDCMono));
  599. #endif
  600.  
  601.     AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);
  602. }
  603.  
  604. BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  605. {
  606.     if (pParentWnd != NULL)
  607.         ASSERT_VALID(pParentWnd);   // must have a parent
  608.  
  609.     // save the style
  610.     m_dwStyle = dwStyle;
  611.     if (nID == AFX_IDW_TOOLBAR)
  612.         m_dwStyle |= CBRS_HIDE_INPLACE;
  613.  
  614.     // create the HWND
  615.     CRect rect;
  616.     rect.SetRectEmpty();
  617.     LPCTSTR lpszClass = AfxRegisterWndClass(0, ::LoadCursor(NULL, IDC_ARROW),
  618.         (HBRUSH)(COLOR_BTNFACE+1), NULL);
  619.     if (!CWnd::Create(lpszClass, NULL, dwStyle, rect, pParentWnd, nID))
  620.         return FALSE;
  621.  
  622.     // Note: Parent must resize itself for control bar to be resized
  623.  
  624.     return TRUE;
  625. }
  626.  
  627. void CToolBar::SetSizes(SIZE sizeButton, SIZE sizeImage)
  628. {
  629.     ASSERT_VALID(this);
  630.     ASSERT(sizeButton.cx > 0 && sizeButton.cy > 0);
  631.     ASSERT(sizeImage.cx > 0 && sizeImage.cy > 0);
  632.  
  633.     // button must be big enough to hold image + 3 pixels on each side
  634.     ASSERT(sizeButton.cx >= sizeImage.cx + 6);
  635.     ASSERT(sizeButton.cy >= sizeImage.cy + 6);
  636.  
  637.     m_sizeButton = sizeButton;
  638.     m_sizeImage = sizeImage;
  639.  
  640.     // set height
  641.     Invalidate();   // just to be nice if called when toolbar is visible
  642. }
  643.  
  644. void CToolBar::SetHeight(int cyHeight)
  645. {
  646.     ASSERT_VALID(this);
  647.  
  648.     int nHeight = cyHeight;
  649.     if (m_dwStyle & CBRS_BORDER_TOP)
  650.         cyHeight -= globalData.cyBorder2;
  651.     if (m_dwStyle & CBRS_BORDER_BOTTOM)
  652.         cyHeight -= globalData.cyBorder2;
  653.     m_cyBottomBorder = (cyHeight - m_sizeButton.cy) / 2;
  654.     // if there is an extra pixel, m_cyTopBorder will get it
  655.     m_cyTopBorder = cyHeight - m_sizeButton.cy - m_cyBottomBorder;
  656.     if (m_cyTopBorder < 0)
  657.     {
  658.         TRACE1("Warning: CToolBar::SetHeight(%d) is smaller than button.\n",
  659.             nHeight);
  660.         m_cyBottomBorder += m_cyTopBorder;
  661.         m_cyTopBorder = 0;  // will clip at bottom
  662.     }
  663.     // bottom border will be ignored (truncate as needed)
  664.     Invalidate();   // just to be nice if called when toolbar is visible
  665. }
  666.  
  667. BOOL CToolBar::LoadBitmap(UINT nIDBitmap)
  668. {
  669.     return LoadBitmap(MAKEINTRESOURCE(nIDBitmap));
  670. }
  671.  
  672. BOOL CToolBar::LoadBitmap(LPCTSTR lpszResourceName)
  673. {
  674.     ASSERT_VALID(this);
  675.     ASSERT(lpszResourceName != NULL);
  676.  
  677.     AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);     // get rid of old one
  678.  
  679.     m_hInstImageWell = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
  680.     if ((m_hRsrcImageWell = ::FindResource(m_hInstImageWell,
  681.         lpszResourceName, RT_BITMAP)) == NULL)
  682.         return FALSE;
  683.  
  684. #ifndef _MAC
  685.     m_hbmImageWell = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
  686. #else
  687.     m_hbmImageWell = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell,
  688.         m_hDCGlyphs, m_bMonochrome);
  689. #endif
  690.     return (m_hbmImageWell != NULL);
  691. }
  692.  
  693. BOOL CToolBar::SetButtons(const UINT* lpIDArray, int nIDCount)
  694. {
  695.     ASSERT_VALID(this);
  696.     ASSERT(nIDCount >= 1);  // must be at least one of them
  697.     ASSERT(lpIDArray == NULL ||
  698.         AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
  699.  
  700.     // first allocate array for panes and copy initial data
  701.     if (!AllocElements(nIDCount, sizeof(AFX_TBBUTTON)))
  702.         return FALSE;
  703.     ASSERT(nIDCount == m_nCount);
  704.  
  705.     if (lpIDArray != NULL)
  706.     {
  707.         int iImage = 0;
  708.         // go through them adding buttons
  709.         AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  710.         for (int i = 0; i < nIDCount; i++, pTBB++)
  711.         {
  712.             ASSERT(pTBB != NULL);
  713.             if ((pTBB->nID = *lpIDArray++) == 0)
  714.             {
  715.                 // separator
  716.                 pTBB->nStyle = TBBS_SEPARATOR;
  717.                 // width of separator includes 2 pixel overlap
  718.                 pTBB->iImage = m_cxDefaultGap + m_cxSharedBorder * 2;
  719.             }
  720.             else
  721.             {
  722.                 // a command button with image
  723.                 pTBB->nStyle = TBBS_BUTTON;
  724.                 pTBB->iImage = iImage++;
  725.             }
  726.         }
  727.     }
  728.     return TRUE;
  729. }
  730.  
  731. #ifdef AFX_CORE3_SEG
  732. #pragma code_seg(AFX_CORE3_SEG)
  733. #endif
  734.  
  735. /////////////////////////////////////////////////////////////////////////////
  736. // CToolBar attribute access
  737.  
  738. int CToolBar::CommandToIndex(UINT nIDFind) const
  739. {
  740.     ASSERT_VALID(this);
  741.  
  742.     AFX_TBBUTTON* pTBB = _GetButtonPtr(0);
  743.     for (int i = 0; i < m_nCount; i++, pTBB++)
  744.         if (pTBB->nID == nIDFind)
  745.             return i;
  746.     return -1;
  747. }
  748.  
  749. UINT CToolBar::GetItemID(int nIndex) const
  750. {
  751.     ASSERT_VALID(this);
  752.  
  753.     return _GetButtonPtr(nIndex)->nID;
  754. }
  755.  
  756. void CToolBar::GetItemRect(int nIndex, LPRECT lpRect) const
  757. {
  758.     ASSERT_VALID(this);
  759.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  760.     ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT)));
  761.  
  762.     BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE;
  763.     CRect rect;
  764.     rect.SetRectEmpty();        // only need top and left
  765.     CalcInsideRect(rect, bHorz);
  766.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  767.     for (int iButton = 0; iButton < nIndex; iButton++, pTBB++)
  768.     {
  769.         ASSERT(pTBB != NULL);
  770.         // skip this button or separator
  771.         if (bHorz)
  772.         {
  773.             rect.left += (pTBB->nStyle & TBBS_SEPARATOR) ?
  774.                         pTBB->iImage : m_sizeButton.cx;
  775.             rect.left -= m_cxSharedBorder;    // go back for overlap
  776.         }
  777.         else
  778.         {
  779.             rect.top += (pTBB->nStyle & TBBS_SEPARATOR) ?
  780.                         pTBB->iImage : m_sizeButton.cy;
  781.             rect.top -= m_cySharedBorder;    // go back for overlap
  782.         }
  783.     }
  784.     ASSERT(iButton == nIndex);
  785.     ASSERT(pTBB == _GetButtonPtr(nIndex));
  786.  
  787.     // button or image width
  788.     if (bHorz)
  789.     {
  790.         int cx = (pTBB->nStyle & TBBS_SEPARATOR) ? pTBB->iImage : m_sizeButton.cx;
  791.         lpRect->right = (lpRect->left = rect.left) + cx;
  792.         lpRect->bottom = (lpRect->top = rect.top) + m_sizeButton.cy;
  793.     }
  794.     else
  795.     {
  796.         int cy = (pTBB->nStyle & TBBS_SEPARATOR) ? pTBB->iImage : m_sizeButton.cy;
  797.         lpRect->bottom = (lpRect->top = rect.top) + cy;
  798.         lpRect->right = (lpRect->left = rect.left) + m_sizeButton.cx;
  799.     }
  800. }
  801.  
  802. UINT CToolBar::GetButtonStyle(int nIndex) const
  803. {
  804.     return _GetButtonPtr(nIndex)->nStyle;
  805. }
  806.  
  807. void CToolBar::SetButtonStyle(int nIndex, UINT nStyle)
  808. {
  809.     AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  810.     UINT nOldStyle = pTBB->nStyle;
  811.     if (nOldStyle != nStyle)
  812.     {
  813.         // update the style and invalidate
  814.         pTBB->nStyle = nStyle;
  815.  
  816.         // invalidate the button only if both styles not "pressed"
  817.         if (!(nOldStyle & nStyle & TBBS_PRESSED))
  818.             InvalidateButton(nIndex);
  819.     }
  820. }
  821.  
  822. CSize CToolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  823. {
  824.     ASSERT_VALID(this);
  825.  
  826.     CSize size = CControlBar::CalcFixedLayout(bStretch, bHorz);
  827.  
  828.     CRect rect;
  829.     rect.SetRectEmpty();        // only need top and left
  830.     CalcInsideRect(rect, bHorz);
  831.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  832.     int nButtonDist = 0;
  833.  
  834.     if (!bStretch)
  835.     {
  836.         for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  837.         {
  838.             ASSERT(pTBB != NULL);
  839.             // skip this button or separator
  840.             nButtonDist += (pTBB->nStyle & TBBS_SEPARATOR) ?
  841.                 pTBB->iImage : (bHorz ? m_sizeButton.cx : m_sizeButton.cy);
  842.             // go back one for overlap
  843.             nButtonDist -= bHorz ? m_cxSharedBorder : m_cySharedBorder;
  844.         }
  845.         if (bHorz)
  846.             size.cx = nButtonDist - rect.Width() + m_cxSharedBorder;
  847.         else
  848.             size.cy = nButtonDist - rect.Height() + m_cySharedBorder;
  849.     }
  850.  
  851.     if (bHorz)
  852.         size.cy = m_sizeButton.cy - rect.Height(); // rect.Height() < 0
  853.     else
  854.         size.cx = m_sizeButton.cx - rect.Width(); // rect.Width() < 0
  855.  
  856.     return size;
  857. }
  858.  
  859. void CToolBar::GetButtonInfo(int nIndex, UINT& nID, UINT& nStyle, int& iImage) const
  860. {
  861.     ASSERT_VALID(this);
  862.  
  863.     AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  864.     nID = pTBB->nID;
  865.     nStyle = pTBB->nStyle;
  866.     iImage = pTBB->iImage;
  867. }
  868.  
  869. void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
  870. {
  871.     ASSERT_VALID(this);
  872.  
  873.     AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  874.     pTBB->nID = nID;
  875.     pTBB->iImage = iImage;
  876.     pTBB->nStyle = nStyle;
  877.     InvalidateButton(nIndex);
  878. }
  879.  
  880. void CToolBar::DoPaint(CDC* pDC)
  881. {
  882.     ASSERT_VALID(this);
  883.     ASSERT_VALID(pDC);
  884.  
  885. #ifdef _MAC
  886. #ifdef _DEBUG
  887.     // turn off validation to speed up button drawing
  888.     int wdSav = WlmDebug(WD_NOVALIDATE | WD_ASSERT);
  889. #endif
  890. #endif
  891.  
  892.     CControlBar::DoPaint(pDC);        // draw border
  893.  
  894.     // if no toolbar loaded, don't draw any buttons
  895.     if (m_hbmImageWell == NULL)
  896.         return;
  897.  
  898.     BOOL bHorz = m_dwStyle & CBRS_ORIENT_HORZ ? TRUE : FALSE;
  899.     CRect rect;
  900.     GetClientRect(rect);
  901.     CalcInsideRect(rect, bHorz);
  902.  
  903.     // force the full size of the button
  904.     if (bHorz)
  905.         rect.bottom = rect.top + m_sizeButton.cy;
  906.     else
  907.         rect.right = rect.left + m_sizeButton.cx;
  908.  
  909.     DrawState ds;
  910.     if (!PrepareDrawButton(ds))
  911.         return;     // something went wrong
  912.  
  913.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  914.     for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  915.     {
  916.         ASSERT(pTBB != NULL);
  917.         if (pTBB->nStyle & TBBS_SEPARATOR)
  918.         {
  919.             // separator
  920.             if (bHorz)
  921.                 rect.right = rect.left + pTBB->iImage;
  922.             else
  923.                 rect.bottom = rect.top + pTBB->iImage;
  924.         }
  925.         else
  926.         {
  927.             if (bHorz)
  928.                 rect.right = rect.left + m_sizeButton.cx;
  929.             else
  930.                 rect.bottom = rect.top + m_sizeButton.cy;
  931.             if (!globalData.bWin32s || pDC->RectVisible(&rect))
  932.             {
  933.                 DrawButton(pDC, rect.left, rect.top,
  934.                     pTBB->iImage, pTBB->nStyle);
  935.             }
  936.         }
  937.         // adjust for overlap
  938.         if (bHorz)
  939.             rect.left = rect.right - m_cxSharedBorder;
  940.         else
  941.             rect.top = rect.bottom - m_cySharedBorder;
  942.     }
  943.     EndDrawButton(ds);
  944.  
  945. #ifdef _MAC
  946. #ifdef _DEBUG
  947.     WlmDebug(wdSav);
  948. #endif
  949. #endif
  950. }
  951.  
  952. void CToolBar::InvalidateButton(int nIndex)
  953. {
  954.     ASSERT_VALID(this);
  955.  
  956.     CRect rect;
  957.     GetItemRect(nIndex, &rect);
  958.     InvalidateRect(rect, FALSE);    // don't erase background
  959. }
  960.  
  961. int CToolBar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  962. {
  963.     ASSERT_VALID(this);
  964.  
  965.     // check child windows first by calling CControlBar
  966.     int nHit = CControlBar::OnToolHitTest(point, pTI);
  967.     if (nHit != -1)
  968.         return nHit;
  969.  
  970.     // now hit test against CToolBar buttons
  971.     nHit = ((CToolBar*)this)->HitTest(point);
  972.     if (nHit != -1)
  973.     {
  974.         AFX_TBBUTTON* pTBB = _GetButtonPtr(nHit);
  975.         if (pTI != NULL)
  976.         {
  977.             GetItemRect(nHit, &pTI->rect);
  978.             pTI->uId = pTBB->nID;
  979.             pTI->hwnd = m_hWnd;
  980.             pTI->lpszText = LPSTR_TEXTCALLBACK;
  981.         }
  982.         nHit = pTBB->nID;
  983.     }
  984.     return nHit;
  985. }
  986.  
  987. int CToolBar::HitTest(CPoint point) // in window relative coords
  988. {
  989.     if (m_pData == NULL)
  990.         return -1;    // no buttons
  991.  
  992.     BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE;
  993.     CRect rect;
  994.     rect.SetRectEmpty();        // only need top and left
  995.     CalcInsideRect(rect, bHorz);
  996.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  997.     ASSERT(pTBB != NULL);
  998.     if (bHorz)
  999.     {
  1000.         if (point.y < rect.top || point.y >= rect.top + m_sizeButton.cy)
  1001.             return -1;      // no Y hit
  1002.         for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  1003.         {
  1004.             if (point.x < rect.left)
  1005.                 break;      // missed it
  1006.             rect.left += (pTBB->nStyle & TBBS_SEPARATOR) ?
  1007.                             pTBB->iImage : m_sizeButton.cx;
  1008.             if (point.x < rect.left && !(pTBB->nStyle & TBBS_SEPARATOR))
  1009.                 return iButton;     // hit !
  1010.             rect.left -= m_cxSharedBorder;    // go back for overlap
  1011.         }
  1012.     }
  1013.     else
  1014.     {
  1015.         if (point.x < rect.left || point.x >= rect.left + m_sizeButton.cx)
  1016.             return -1;      // no X hit
  1017.         for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  1018.         {
  1019.             if (point.y < rect.top)
  1020.                 break;      // missed it
  1021.             rect.top += (pTBB->nStyle & TBBS_SEPARATOR) ?
  1022.                             pTBB->iImage : m_sizeButton.cy;
  1023.             if (point.y < rect.top && !(pTBB->nStyle & TBBS_SEPARATOR))
  1024.                 return iButton;     // hit !
  1025.             rect.top -= m_cySharedBorder;    // go back for overlap
  1026.         }
  1027.     }
  1028.  
  1029.     return -1;      // nothing hit
  1030. }
  1031.  
  1032. /////////////////////////////////////////////////////////////////////////////
  1033. // CToolBar message handlers
  1034.  
  1035. BEGIN_MESSAGE_MAP(CToolBar, CControlBar)
  1036.     //{{AFX_MSG_MAP(CToolBar)
  1037.     ON_WM_LBUTTONDOWN()
  1038.     ON_WM_MOUSEMOVE()
  1039.     ON_WM_LBUTTONUP()
  1040.     ON_WM_CANCELMODE()
  1041.     ON_WM_SYSCOLORCHANGE()
  1042.     //}}AFX_MSG_MAP
  1043. END_MESSAGE_MAP()
  1044.  
  1045. void CToolBar::OnLButtonDown(UINT nFlags, CPoint point)
  1046. {
  1047.     if ((m_iButtonCapture = HitTest(point)) < 0) // nothing hit
  1048.     {
  1049.         CControlBar::OnLButtonDown(nFlags, point);
  1050.         return;
  1051.     }
  1052.  
  1053.     AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  1054.     ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  1055.  
  1056.     // update the button before checking for disabled status
  1057.     UpdateButton(m_iButtonCapture);
  1058.     if (pTBB->nStyle & TBBS_DISABLED)
  1059.     {
  1060.         m_iButtonCapture = -1;
  1061.         return;     // don't press it
  1062.     }
  1063.  
  1064.     pTBB->nStyle |= TBBS_PRESSED;
  1065.     InvalidateButton(m_iButtonCapture);
  1066.     UpdateWindow(); // immediate feedback
  1067.     SetCapture();
  1068.     GetOwner()->SendMessage(WM_SETMESSAGESTRING, (WPARAM)pTBB->nID);
  1069. }
  1070.  
  1071. void CToolBar::OnMouseMove(UINT /*nFlags*/, CPoint point)
  1072. {
  1073.     if (m_iButtonCapture >= 0)
  1074.     {
  1075.         AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  1076.         ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  1077.  
  1078.         UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
  1079.         int iButtonCapture = m_iButtonCapture;
  1080.         if (GetCapture() != this)
  1081.         {
  1082.             m_iButtonCapture = -1; // lost capture
  1083.             GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
  1084.         }
  1085.         else
  1086.         {
  1087.             // should be pressed if still hitting the captured button
  1088.             if (HitTest(point) == m_iButtonCapture)
  1089.                 nNewStyle |= TBBS_PRESSED;
  1090.         }
  1091.         SetButtonStyle(iButtonCapture, nNewStyle);
  1092.         UpdateWindow(); // immediate feedback
  1093.     }
  1094. }
  1095.  
  1096. void CToolBar::OnLButtonUp(UINT nFlags, CPoint point)
  1097. {
  1098.     if (m_iButtonCapture < 0)
  1099.     {
  1100.         CControlBar::OnLButtonUp(nFlags, point);
  1101.         return;     // not captured
  1102.     }
  1103.  
  1104.     AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  1105.     ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  1106.     UINT nIDCmd = 0;
  1107.  
  1108.     UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
  1109.     if (GetCapture() == this)
  1110.     {
  1111.         // we did not lose the capture
  1112.         ReleaseCapture();
  1113.         if (HitTest(point) == m_iButtonCapture)
  1114.         {
  1115.             // give button a chance to update
  1116.             UpdateButton(m_iButtonCapture);
  1117.  
  1118.             // then check for disabled state
  1119.             if (!(pTBB->nStyle & TBBS_DISABLED))
  1120.             {
  1121.                 // pressed, will send command notification
  1122.                 nIDCmd = pTBB->nID;
  1123.  
  1124.                 if (pTBB->nStyle & TBBS_CHECKBOX)
  1125.                 {
  1126.                     // auto check: three state => down
  1127.                     if (nNewStyle & TBBS_INDETERMINATE)
  1128.                         nNewStyle &= ~TBBS_INDETERMINATE;
  1129.  
  1130.                     nNewStyle ^= TBBS_CHECKED;
  1131.                 }
  1132.             }
  1133.         }
  1134.     }
  1135.  
  1136.     GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
  1137.  
  1138.     int iButtonCapture = m_iButtonCapture;
  1139.     m_iButtonCapture = -1;
  1140.     if (nIDCmd != 0)
  1141.         GetOwner()->SendMessage(WM_COMMAND, nIDCmd);    // send command
  1142.  
  1143.     SetButtonStyle(iButtonCapture, nNewStyle);
  1144.     UpdateButton(iButtonCapture);
  1145.  
  1146.     UpdateWindow(); // immediate feedback
  1147. }
  1148.  
  1149. void CToolBar::OnCancelMode()
  1150. {
  1151.     CControlBar::OnCancelMode();
  1152.  
  1153.     if (m_iButtonCapture >= 0)
  1154.     {
  1155.         AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  1156.         ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  1157.         UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
  1158.         if (GetCapture() == this)
  1159.             ReleaseCapture();
  1160.         SetButtonStyle(m_iButtonCapture, nNewStyle);
  1161.         m_iButtonCapture = -1;
  1162.         UpdateWindow();
  1163.     }
  1164. }
  1165.  
  1166. void CToolBar::OnSysColorChange()
  1167. {
  1168. #ifdef _MAC
  1169.     CControlBar::OnSysColorChange();
  1170.  
  1171.     ASSERT(hDCGlyphs != NULL);
  1172.     VERIFY(::DeleteDC(hDCGlyphs));
  1173.     hDCGlyphs = ::CreateCompatibleDC(NULL);
  1174.  
  1175.     ASSERT(hDCMono != NULL);
  1176.     VERIFY(::DeleteDC(hDCMono));
  1177.     hDCMono = ::CreateCompatibleDC(NULL);
  1178. #endif
  1179.  
  1180.     // re-initialize global dither brush
  1181. #ifndef _MAC
  1182.     HBITMAP hbmGray = ::CreateDitherBitmap();
  1183. #else
  1184.     HBITMAP hbmGray = ::CreateDitherBitmap(m_bMonochrome);
  1185. #endif
  1186.     if (hbmGray != NULL)
  1187.     {
  1188.         HBRUSH hbrNew = ::CreatePatternBrush(hbmGray);
  1189.         if (hbrNew != NULL)
  1190.         {
  1191.             AfxDeleteObject((HGDIOBJ*)&hbrDither);      // free old one
  1192.             hbrDither = hbrNew;
  1193.         }
  1194.         ::DeleteObject(hbmGray);
  1195.     }
  1196.  
  1197.     // re-color bitmap for toolbar
  1198.     if (m_hbmImageWell != NULL)
  1199.     {
  1200.         HBITMAP hbmNew;
  1201. #ifndef _MAC
  1202.         hbmNew = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
  1203. #else
  1204.         hbmNew = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell,
  1205.             m_hDCGlyphs, m_bMonochrome);
  1206. #endif
  1207.         if (hbmNew != NULL)
  1208.         {
  1209.             ::DeleteObject(m_hbmImageWell);     // free old one
  1210.             m_hbmImageWell = hbmNew;
  1211.         }
  1212.     }
  1213. }
  1214.  
  1215. /////////////////////////////////////////////////////////////////////////////
  1216. // CToolBar idle update through CToolCmdUI class
  1217.  
  1218. #define CToolCmdUI COldToolCmdUI
  1219.  
  1220. class CToolCmdUI : public CCmdUI        // class private to this file !
  1221. {
  1222. public: // re-implementations only
  1223.     virtual void Enable(BOOL bOn);
  1224.     virtual void SetCheck(int nCheck);
  1225.     virtual void SetText(LPCTSTR lpszText);
  1226. };
  1227.  
  1228. void CToolCmdUI::Enable(BOOL bOn)
  1229. {
  1230.     m_bEnableChanged = TRUE;
  1231.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1232.     ASSERT(pToolBar != NULL);
  1233.     ASSERT_KINDOF(CToolBar, pToolBar);
  1234.     ASSERT(m_nIndex < m_nIndexMax);
  1235.  
  1236.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
  1237.     if (!bOn)
  1238.         nNewStyle |= TBBS_DISABLED;
  1239.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1240.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
  1241. }
  1242.  
  1243. void CToolCmdUI::SetCheck(int nCheck)
  1244. {
  1245.     ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
  1246.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1247.     ASSERT(pToolBar != NULL);
  1248.     ASSERT_KINDOF(CToolBar, pToolBar);
  1249.     ASSERT(m_nIndex < m_nIndexMax);
  1250.  
  1251.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) &
  1252.                 ~(TBBS_CHECKED | TBBS_INDETERMINATE);
  1253.     if (nCheck == 1)
  1254.         nNewStyle |= TBBS_CHECKED;
  1255.     else if (nCheck == 2)
  1256.         nNewStyle |= TBBS_INDETERMINATE;
  1257.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1258.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX);
  1259. }
  1260.  
  1261. void CToolCmdUI::SetText(LPCTSTR)
  1262. {
  1263.     // ignore it
  1264. }
  1265.  
  1266. void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  1267. {
  1268.     CToolCmdUI state;
  1269.     state.m_pOther = this;
  1270.  
  1271.     state.m_nIndexMax = (UINT)m_nCount;
  1272.     for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
  1273.       state.m_nIndex++)
  1274.     {
  1275.         AFX_TBBUTTON* pTBB = _GetButtonPtr(state.m_nIndex);
  1276.         state.m_nID = pTBB->nID;
  1277.  
  1278.         // ignore separators
  1279.         if (!(pTBB->nStyle & TBBS_SEPARATOR))
  1280.             state.DoUpdate(pTarget, bDisableIfNoHndler);
  1281.     }
  1282.  
  1283.     // update the dialog controls added to the toolbar
  1284.     UpdateDialogControls(pTarget, bDisableIfNoHndler);
  1285. }
  1286.  
  1287. void CToolBar::UpdateButton(int nIndex)
  1288. {
  1289.     // determine target of command update
  1290.     CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
  1291.     if (pTarget == NULL || !pTarget->IsFrameWnd())
  1292.         pTarget = GetParentFrame();
  1293.  
  1294.     // send the update notification
  1295.     if (pTarget != NULL)
  1296.     {
  1297.         CToolCmdUI state;
  1298.         state.m_pOther = this;
  1299.         state.m_nIndex = nIndex;
  1300.         state.m_nIndexMax = (UINT)m_nCount;
  1301.         AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  1302.         state.m_nID = pTBB->nID;
  1303.         state.DoUpdate(pTarget, pTarget->m_bAutoMenuEnable);
  1304.     }
  1305. }
  1306.  
  1307. /////////////////////////////////////////////////////////////////////////////
  1308. // CToolBar diagnostics
  1309.  
  1310. #ifdef _DEBUG
  1311. void CToolBar::AssertValid() const
  1312. {
  1313.     CControlBar::AssertValid();
  1314.     ASSERT(m_hbmImageWell == NULL ||
  1315.         (globalData.bWin32s || ::GetObjectType(m_hbmImageWell) == OBJ_BITMAP));
  1316.  
  1317.     if (m_hbmImageWell != NULL)
  1318.     {
  1319.         ASSERT(m_hRsrcImageWell != NULL);
  1320.         ASSERT(m_hInstImageWell != NULL);
  1321.     }
  1322. }
  1323.  
  1324. void CToolBar::Dump(CDumpContext& dc) const
  1325. {
  1326.     CControlBar::Dump(dc);
  1327.  
  1328.     dc << "m_hbmImageWell = " << (UINT)m_hbmImageWell;
  1329.     dc << "\nm_hInstImageWell = " << (UINT)m_hInstImageWell;
  1330.     dc << "\nm_hRsrcImageWell = " << (UINT)m_hRsrcImageWell;
  1331.     dc << "\nm_iButtonCapture = " << m_iButtonCapture;
  1332.     dc << "\nm_sizeButton = " << m_sizeButton;
  1333.     dc << "\nm_sizeImage = " << m_sizeImage;
  1334.  
  1335.     if (dc.GetDepth() > 0)
  1336.     {
  1337.         for (int i = 0; i < m_nCount; i++)
  1338.         {
  1339.             AFX_TBBUTTON* pTBB = _GetButtonPtr(i);
  1340.             dc << "\ntoolbar button[" << i << "] = {";
  1341.             dc << "\n\tnID = " << pTBB->nID;
  1342.             dc << "\n\tnStyle = " << pTBB->nStyle;
  1343.             if (pTBB->nStyle & TBBS_SEPARATOR)
  1344.                 dc << "\n\tiImage (separator width) = " << pTBB->iImage;
  1345.             else
  1346.                 dc <<"\n\tiImage (bitmap image index) = " << pTBB->iImage;
  1347.             dc << "\n}";
  1348.         }
  1349.     }
  1350.  
  1351.     dc << "\n";
  1352. }
  1353. #endif
  1354.  
  1355. #undef new
  1356. #ifdef AFX_INIT_SEG
  1357. #pragma code_seg(AFX_INIT_SEG)
  1358. #endif
  1359.  
  1360. IMPLEMENT_DYNAMIC(CToolBar, CControlBar)
  1361.